package com.aim.config.shiro;

import com.aim.common.util.ConverterUtils;
import com.aim.entity.system.SysUser;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.HashSet;
import java.util.List;

/**
 * @AUTO 自定义授权
 * @Author AIM
 * @DATE 2019/4/23
 */
public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UserAuthService shiroFactory = UserAuthService.me();
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        SysUser user = shiroFactory.user(token.getUsername());
        ShiroUser shiroUser = shiroFactory.shiroUser(user);
        // 数据库中用户密码
        String credentials = user.getPassword();
        // 密码加盐处理
        String source = user.getSalt();
        ByteSource credentialsSalt = new Md5Hash(source);
        return new SimpleAuthenticationInfo(shiroUser, credentials, credentialsSalt, super.getName());
    }

    /**
     * 权限认证
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        ShiroUser shiroUser = (ShiroUser) principalCollection.getPrimaryPrincipal();
        if (shiroUser != null) {
            //权限信息对象info,用来存放查出的用户的所有的角色（role）及权限（permission）
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            StringBuffer sb = new StringBuffer();
            sb.append("SELECT URL FROM `sys_role_menu` rel INNER JOIN sys_menu m ON rel.MENU_ID = m.MENU_ID WHERE rel.ROLE_ID = ? ");
            List<String> auths = this.jdbcTemplate.queryForList(sb.toString(), new Object[]{shiroUser.getRoleId()}, String.class);
            //用户的权限集合
            info.addStringPermissions(new HashSet(auths));
            List<Long> roleList = shiroUser.getRoleList();
            // 查询角色
            sb.setLength(0);
            sb.append("SELECT `DESCRIPTION` FROM `sys_role` WHERE `ROLE_ID` in (");
            for (Long roleId : roleList) {
                sb.append("?,");
            }
            if (sb.toString().endsWith(",")) {
                sb.deleteCharAt(sb.length() - 1);
            }
            sb.append(")");
            List<String> roles = jdbcTemplate.queryForList(sb.toString(), ConverterUtils.list2Array(roleList), String.class);
            //用户的角色集合
            info.addRoles(new HashSet(roles));

            return info;
        }
        // 返回null的话，就会导致任何用户访问被拦截的请求时，都会自动跳转到unauthorizedUrl指定的地址
        return null;
    }

    /**
     * 设置认证加密方式
     */
    @Override
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        HashedCredentialsMatcher md5CredentialsMatcher = new HashedCredentialsMatcher();
        md5CredentialsMatcher.setHashAlgorithmName(ShiroKit.hashAlgorithmName);
        md5CredentialsMatcher.setHashIterations(ShiroKit.hashIterations);
        super.setCredentialsMatcher(md5CredentialsMatcher);
    }
}
